#pragma once
#include <iostream>
#include <string>
#include "myh/socket.hpp"
#include "myh/MyLog.hpp"
#include "myh/pthreadpool.hpp"
#include <unordered_map>
#include <functional>
#include "serialization.hpp"
#include "ComTask.hpp"
#include <unistd.h>
class tcpserve
{
    typedef std::function<void(sockaddr_in *, int)> Task;
    typedef std::shared_ptr<tcpserve> TcpPtr;
    typedef std::shared_ptr<Socket> SocketPtr;
    typedef std::shared_ptr<std::unordered_map<std::string, uint16_t>> ClientDate;
    static const char *defaultip;
    static const size_t SIZE = 1024;
    static void funrun(sockaddr_in *addr, int fd)
    {
        while (true)
        {
            char buffer[SIZE];
            int n = read(fd, buffer, SIZE);
            if (n == 0)
            {
                lg(Normol, "客户端正常退出...");
                break;
            }
            else if (n > 0)
            {
                buffer[n] = 0;
                // 收到正常请求,回复请求
                std::string s = buffer;
                std::cout << "收到请求:" << s << std::endl;
                s = ComTask(s);
                _this->RetClient(s, fd);
            }
            else
            {
                lg.defaultprint("read", errno);
                // 写入错误尝试重新写入
                break;
            }
        }
    }

    void RetClient(std::string &s, int fd)
    {
        std::cout << "回复请求:" << s << std::endl;
        int n = write(fd, s.c_str(), s.size());
        if (n < 0)
        {
            lg.defaultprint("write", errno);
            // 尝试重新发送
        }
    }

    void Addclient(sockaddr_in *clientaddr)
    {
        char ip[16];
        inet_ntop(AF_INET, &(clientaddr->sin_addr), ip, 16);
        uint16_t port = ntohl(clientaddr->sin_port);
        _this->_cdate->insert({ip, port});
        lg(Debug, "[%s-%d][用户ip:%s:%ld链接成功]", __FILE__, __LINE__, ip, port);
    }

    class ClientFd
    {
    public:
        ClientFd(Task task, const sockaddr_in &addr, int fd)
            : _task(std::move(task)), _addr(addr), _fd(fd)
        {
        }
        ClientFd(const ClientFd &) = default;
        ClientFd(ClientFd &&) = default;
        ClientFd &operator=(const ClientFd &) = default;
        ClientFd &operator=(ClientFd &&) = default;
        void operator()()
        {
            _task(&_addr, _fd);
        }

    private:
        Task _task;
        sockaddr_in _addr;
        int _fd;
    };

public:
    void run()
    {
        _this->_csocket->Bind();
        _this->_csocket->Listen();
        PthPool<ClientFd>::Getinitance();
        PthPool<ClientFd>::Getinitance()->start();
        sockaddr_in clientaddr;
        char ip[16];

        while (true)
        {
            lg.ChangeFilePath(Screnn);
            std::cout << "等待连接..." << std::endl;
            _fd = _this->_csocket->Accept(&clientaddr);

            inet_ntop(AF_INET, &(clientaddr.sin_addr), ip, 16);
            uint16_t port = ntohl(clientaddr.sin_port);
            // _this->_cdate->insert({ip, port});
            std::cout << "链接成功...ip:" << ip << " port:" << port << std::endl;
            // Addclient(&clientaddr);
            PthPool<ClientFd>::Getinitance()->push(ClientFd(funrun, clientaddr, _fd));
        }
    }

    static TcpPtr Getinitance(uint16_t port = 0, const std::string &ip = defaultip, int domain = AF_INET, int type = SOCK_STREAM)
    {
        static std::once_flag once;
        std::call_once(once, [port, ip, domain, type]()
                       { _this = TcpPtr(new tcpserve(port, ip, domain, type)); });
        return _this;
    }

private:
    tcpserve(const tcpserve &u) = delete;
    tcpserve &operator=(const tcpserve &u) = delete;
    tcpserve(uint16_t port, const std::string &ip = defaultip, int domain = AF_INET, int type = SOCK_STREAM)
        : _csocket(SocketPtr(new Socket(port, ip, domain, type)))
    {
    }

private:
    int _fd = 0;
    SocketPtr _csocket;
    ClientDate _cdate;
    static TcpPtr _this;
};

tcpserve::TcpPtr tcpserve::_this = nullptr;
const char *tcpserve::defaultip = "0.0.0.0";
